/***************************************************************************************
The ISO/IEC JTC1/SC29/WG11 (MPEG). Internet Video Coding Test Model
The software is developed by Peking University, Tsinghua University and Zhejiang University etc. 
* Main developers include but are not limited as follows:  
Ronggang Wang, Peking University, Shenzhen Graduate School, rgwang@pkusz.edu.cn,  
Xianguo Zhang,   Peking University
Hao Lv,  Peking University, Shenzhen Graduate School
Zhenyu Wang,  Peking University, Shenzhen Graduate School
Xingguo Zhu,  Zhejiang University
Jianwen Chen,  Tsinghua University
Li Zhang,  Peking University
Siwei Ma,  Peking University
Qin Yu, Peking University
etc.
***************************************************************************************/


#include "contributors.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/timeb.h>
#include <assert.h>

#if defined WIN32
#include <conio.h>
#include <IO.H>
#include <FCNTL.H>
#endif

#include "global.h"
#include "memalloc.h"
#include "annexb.h"
#include "bbv.h"  
#include "header.h"
#include "AEC.h" 
#include "common.h"

#define ITM          "15.0"
#define VERSION     "201606"

#define LOGFILE     "log.dec"


#define DATADECFILE "dataDec.txt"
#define TRACEFILE   "trace_dec.txt"

#define _S_IREAD        0000400         /* read permission, owner */
#define _S_IWRITE       0000200         /* write permission, owner */

extern FILE* bits;

inp_params    *input;       //!< input parameters from input configuration file
snr_par    *snr;
img_params    *img;         //!< image parameters
StatBits *StatBitsPtr;	

Bitstream *currStream;
FILE *reffile,*reffile2;

extern BbvBuffer_t *pBbv; 

/*
*************************************************************************
* Function:main function for decoder
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/
int main(int argc, char **argv)
{
	int i;

  // allocate memory for the structures
	if ((input =  (inp_params *)calloc(1, sizeof(inp_params)))==NULL) no_mem_exit("main: input");
	if ((snr =  (snr_par *)calloc(1, sizeof(snr_par)))==NULL) no_mem_exit("main: snr");
	if ((img =  (img_params *)calloc(1, sizeof(img_params)))==NULL) no_mem_exit("main: img");

	if ((StatBitsPtr =  (struct StatBits *)calloc(1, sizeof(struct StatBits)))==NULL) no_mem_exit("main: StatBits");

	img->seq_header_indicate = 0;   
	img->B_discard_flag = 0;        
	StatBitsPtr->curr_frame_bits = StatBitsPtr->prev_frame_bits
	= StatBitsPtr->emulate_bits = StatBitsPtr->last_unit_bits = 0; //ITM_r2
	StatBitsPtr->bitrate = StatBitsPtr->coded_pic_num = StatBitsPtr->time_s = 0; //ITM_r2

	currStream = AllocBitstream();

	eos = 0;
	CSyntax = 1;

	init_conf(input,argc,argv);

	OpenBitstreamFile (input->infile);

	if(input->ref_pic_order) {    //ref order
		dec_ref_num = 0;
	}
	malloc_slice(input, img);

    com_funs_init_ip_filter();
	com_funs_init_intra_pred();
	com_funs_init_deblock_filter();
	com_funs_init_dct();
	com_funs_init_pixel_opt();

	#if ENABLE_SSE
	com_init_intrinsic();
	#endif
	#if ENABLE_AVX2
	//com_init_intrinsic_256();
	#endif

	// initialize the table of square values used in snr calculation
	for (i=0; i <  256; i++)
	{
		img->tab_sqr[i]=i*i; 
	}

	img->number=0;
	img->type = I_IMG;
	img->imgtr_last_P = 0;
	img->imgtr_next_P = 0;

	img->new_seq_header_flag = 1; 
	img->new_sequence_flag   = 1; 

	vec_flag = 0;

	FrameNum = 0;

	// B pictures
	Bframe_ctr=0;

	// time for total decoding session
	tot_time = 0;
	do { 
		while ((decode_one_frame(img, input, snr) != EOS) && (!IsEndOfBitstream()));
	} while (!IsEndOfBitstream()); 

	if(CSyntax)
	fprintf(p_sreport, "\nALL SYNTAX IS CORRECT!\n");
  
	if(StatBitsPtr->time_s==0)
	StatBitsPtr->total_bitrate[StatBitsPtr->time_s++] = StatBitsPtr->bitrate;

	eos = 1;	
	if (p_ref && !input->ref_pic_order) 
	{  //ref order
		find_snr(snr,img,p_ref, img_prev);      // if ref sequence exist
	}
	else 
	{
		find_snr(snr,img,p_ref, img_prev);      // if ref sequence exist
	}

	if(pre_img_type == I_IMG && !input->ref_pic_order) // I picture, ref order
	{
		fprintf(stdout,"%3d(I)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s %8d %6d\n",
		FrameNum, pre_img_tr, pre_img_qp,snr->snr_y,snr->snr_u,snr->snr_v,pre_tmp_time,"FRM",StatBitsPtr->prev_frame_bits,StatBitsPtr->prev_emulate_bits);
	} 
	else if(pre_img_type == P_IMG && !input->ref_pic_order) // P pictures
	{
	if (pre_img_types == I_IMG)
		fprintf(stdout,"%3d(I)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s %8d %6d\n",
		FrameNum, pre_img_tr, pre_img_qp,snr->snr_y,snr->snr_u,snr->snr_v,pre_tmp_time,"FRM",StatBitsPtr->prev_frame_bits,StatBitsPtr->prev_emulate_bits);   
	else
		fprintf(stdout,"%3d(P)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s %8d %6d\n",
		FrameNum, pre_img_tr, pre_img_qp,snr->snr_y,snr->snr_u,snr->snr_v,pre_tmp_time,"FRM",StatBitsPtr->prev_frame_bits,StatBitsPtr->prev_emulate_bits);
	}

	report_frame(snr,pre_tmp_time);

    // B PICTURE : save the last P picture
	if (input->output_dec_pic)  // output_dec_pic
	write_prev_Pframe(img, p_out, img_prev);

	if (input->check_BBV_flag)
	{
		stat_bbv_buffer(pBbv);
		pBbv = free_bbv_memory(pBbv);
		printf("min bbv_buffer_size in bitstream is %d\n", ((pminBBSsize>>14) + (pminBBSsize&0x3FFF? 1 : 0))); 
		if (!pbbv_mode) 
		{
			printf("min initial bbv_delay(0) time is %.4f(s)\n", (float)pminFsize/pbitrate);
		}
	}

	if (img->sequence_end_flag)  
		fprintf(stdout, "Sequence End\n\n");

	{
		int i;
		float framerate[8]={24000/1001,24,25,30000/1001,30,50,60000/1001,60};  
		if( (int)(StatBitsPtr->coded_pic_num - (StatBitsPtr->time_s+1)*framerate[frame_rate_code-1] + 0.5) == 0 )
		{
			StatBitsPtr->total_bitrate[StatBitsPtr->time_s++] = StatBitsPtr->bitrate;
			CheckBitrate(StatBitsPtr->bitrate,StatBitsPtr->time_s);
			StatBitsPtr->bitrate = 0;
		}
		StatBitsPtr->total_bitrate[StatBitsPtr->time_s-1] += 32;
		printf("Second(s)\tBitrate(bit/s)\n");
		for(i=0; i<StatBitsPtr->time_s; i++)
		{	  
			printf(" %3d\t\t %d\n", i, StatBitsPtr->total_bitrate[i]);
		}
		if(StatBitsPtr->time_s==0)
			printf(" %3d\t\t %d\n", 0, StatBitsPtr->total_bitrate[0]);
	}

	report(input, img, snr);


	FreeBitstream();
	free_slice(img); 
	free_global_buffers(img);

	CloseBitstreamFile();

	fclose(p_out);
	if (p_ref)
		fclose(p_ref);  

#if TRACE
	fclose(p_trace);
#endif

	if(p_sreport) 
		fclose(p_sreport);

	free (input);
	free (snr);
	free (img);

	//system("pause");
	return 0;
}

/*
*************************************************************************
* Function:Read input from configuration file
* Input:Name of configuration filename
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void init_conf(inp_params *inp, int numpar,char **config_str)
{
  FILE *fd = NULL;

  inp->check_BBV_flag = 0; 

  // read the decoder configuration file
  if( numpar != 1 && numpar != 2 && numpar != 9 && numpar != 10 && numpar != 11  && numpar != 12 )
  {
    snprintf(errortext, ET_SIZE, 
      "Usage: %s <config.dat> <IVCfilename> <decfilename> <reffilename> <ref_num> <lfdisable> <yuv_structure> <bbv_check>\n \
      ?-the decoder can be configured by configfile or by command line \n \
      ?-param with only <config.dat> defines decoder with file\n \
      ?-params with allof the params define decoder params with command line\n \
      ",config_str[0]);
    error(errortext, 300);
  }

  if(numpar == 1) {
    fprintf(stdout, "**************************************************************************\n");
    fprintf(stdout, "The decoder config file doesn't exist. Use the default parameters instead!\n");
    fprintf(stdout, "**************************************************************************\n\n");
  }

  if(numpar != 1) 
    if((fd=fopen(config_str[1],"r")) == NULL)
    {
      snprintf(errortext, ET_SIZE, "Error: Control file %s not found\n",config_str[1]);
      error(errortext, 300);
    }

    strcpy(inp->infile, "test.IVC");
    strcpy(inp->outfile, "test_dec.yuv");
    strcpy(inp->reffile, "test_rec.yuv");
    inp->buf_cycle = 2;
    inp->check_BBV_flag = 0;
    inp->output_syntaxcheck = 0;
    inp->ref_pic_order  = 0;
    inp->output_dec_pic = 1;


    if(numpar != 1){
      fscanf(fd,"%s",inp->infile);                // IVC compressed input bitsream
      fscanf(fd,"%*[^\n]");

      fscanf(fd,"%s",inp->outfile);               // YUV output format
      fscanf(fd,"%*[^\n]");

      fscanf(fd,"%s",inp->reffile);               // reference file
      fscanf(fd,"%*[^\n]");
    }

    if(numpar == 2)  { //ref order
      fscanf(fd,"%d,",&inp->buf_cycle);           
      fscanf(fd,"%*[^\n]");

      fscanf(fd,"%d,",&inp->yuv_structure);      
      fscanf(fd,"%*[^\n]");

      fscanf(fd,"%d,",&inp->check_BBV_flag);
      fscanf(fd,"%*[^\n]");

      fscanf(fd,"%d,",&inp->output_syntaxcheck); 
      fscanf(fd,"%*[^\n]");
    }

    if (numpar == 8 || numpar == 9 || numpar == 10 || numpar == 11) //The decoder will be configured with the command line in the case of 9 parameters input
    { 

      strcpy(inp->infile,config_str[2]);
      strcpy(inp->outfile,config_str[3]);
      strcpy(inp->reffile,config_str[4]);

      inp->buf_cycle = atoi(config_str[5]); 

      inp->check_BBV_flag = atoi(config_str[7]); 
    }
    if (numpar == 9 || numpar == 10 || numpar == 11)
    {
      inp->output_syntaxcheck = atoi(config_str[8]);
    }
    if (numpar == 10 || numpar == 11)
    {
      inp->ref_pic_order  = atoi(config_str[9]);
    }
    if (numpar == 11)
    {
      inp->output_dec_pic  = atoi(config_str[10]);  //output_dec_pic
    }
    if (inp->buf_cycle < 1)
    {
      snprintf(errortext, ET_SIZE, "Frame Buffer Size is %d. It has to be at least 1",inp->buf_cycle);
      error(errortext,1);
    }

#if TRACE
    if ((p_trace=fopen(TRACEFILE,"w"))==0)             // append new statistic at the end
    {
      snprintf(errortext, ET_SIZE, "Error open file %s!",TRACEFILE);
      error(errortext,500);
    }
#endif

    if (inp->output_syntaxcheck)
    {
      p_sreport=fopen("syntaxreport.dat","a+");
    }
    else
    {
      p_sreport=fopen("syntaxreport.dat","w+");
    }
    if (p_sreport==0)
    {
      snprintf(errortext, ET_SIZE, "Error open file %s!","syntaxreport.dat");
      error(errortext,500);
    }

    //ITM
    fprintf(p_sreport, "\n-----------------------------------------------------------------\n");
    fprintf(p_sreport, "*****************************************************************\n");
    fprintf(p_sreport, "**THE SYNTAX CHECKING MECHANISM IS BASED ON N1572'S DESCRIPTION**\n");
    fprintf(p_sreport, "*****************************************************************\n");
    fprintf(p_sreport, "File Name: %s", input->infile);  
    fprintf(p_sreport, "\nUsage:\n");
    fprintf(p_sreport, "Error Code:\n");
    fprintf(p_sreport, "0: Invalid deltaQP. ImageQP out of the range [0,63], section 7.2.5&9.4.7 @ N1572\n");
    fprintf(p_sreport, "1: Quantization coefficient's value out of the range [-2048,2047], section 9.6.4 @ N1572\n");
    fprintf(p_sreport, "2: De-Quantization coefficient's value out of the range [-8192,8191], section 9.6.4 @ N1572\n");
    fprintf(p_sreport, "3: mv_diff_x or mv_diff_y out of the range [-4096, 4095], section 7.2.5 @ N1572\n");
    fprintf(p_sreport, "4: Motion Vector out of the range specified at section B.2 @ N1572\n");
    fprintf(p_sreport, "Example:\n");
    fprintf(p_sreport, "error(0)       (deltaQP,ImgQP) @ MBidx\n");
    fprintf(p_sreport, "error(1)           quant-value @ (y,x) Blkidx MBidx\n");
    fprintf(p_sreport, "error(2)         dequant-value @ (y,x) Blkidx MBidx\n");
    fprintf(p_sreport, "error(3)               mv_diff @ Blkidx MBidx\n");
    fprintf(p_sreport, "error(4)                mv|pos @ Blkidx MBidx\n");
    fprintf(p_sreport, "\nStart To Check The Syntax\n");
    CSyntax = 1;
    //ITM

    if (input->output_dec_pic)  //output_dec_pic
      if ((p_out=fopen(inp->outfile,"wb"))==0)
      {
        snprintf(errortext, ET_SIZE, "Error open file %s ",inp->outfile);
        error(errortext,500);
      }

      fprintf(stdout,"--------------------------------------------------------------------------\n");
      fprintf(stdout," Decoder config file                    : %s \n",config_str[0]);
      fprintf(stdout,"--------------------------------------------------------------------------\n");
      fprintf(stdout," Input IVC bitstream                    : %s \n",inp->infile);
      fprintf(stdout," Output decoded YUV 4:2:0               : %s \n",inp->outfile);
      fprintf(stdout," Output status file                     : %s \n",LOGFILE);

      if ((p_ref=fopen(inp->reffile,"rb"))==0)
      {
        fprintf(stdout," Input reference file                   : %s does not exist \n",inp->reffile);
        fprintf(stdout,"                                          SNR values are not available\n");
        RefPicExist = 0;
      }
      else
      {
        fprintf(stdout," Input reference file                   : %s \n",inp->reffile);
        RefPicExist = 1;
      }

      fprintf(stdout,"--------------------------------------------------------------------------\n");
      fprintf(stdout," Frame   TR    QP   SnrY    SnrU    SnrV   Time(ms)   FRM/FLD  Bits  EmulateBits\n");
}

/*
*************************************************************************
* Function:Reports the gathered information to appropriate outputs
* Input:
inp_params *inp,
img_params *img,
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void report(inp_params *inp, img_params *img, snr_par *snr)
{
#define OUTSTRING_SIZE 255
  char string[OUTSTRING_SIZE];
  FILE *p_log;

  time_t  now;
  struct tm *l_time;

  fprintf(stdout,"-------------------- Average SNR all frames ------------------------------\n");
  fprintf(stdout," SNR Y(dB)           : %5.2f\n",snr->snr_sum_y);
  fprintf(stdout," SNR U(dB)           : %5.2f\n",snr->snr_sum_u);
  fprintf(stdout," SNR V(dB)           : %5.2f\n",snr->snr_sum_v);
  fprintf(stdout," Total decoding time : %.3f sec \n",tot_time*0.001);
  fprintf(stdout,"--------------------------------------------------------------------------\n");
  if(!CSyntax)
    fprintf(stdout, " SOME BITSTREAM SYNTAX IS ILLEGAL, DETAIL CAN BE FOUND AT SYNTAXREPORT.DAT\n");
  fprintf(stdout," Exit ITM %s decoder, ver %s ",ITM, VERSION);
  fprintf(stdout,"\n");

  snprintf(string, OUTSTRING_SIZE, "%s", LOGFILE);
  if ((p_log=fopen(string,"r"))==0)                    // check if file exist
  {
    if ((p_log=fopen(string,"a"))==0)
    {
      snprintf(errortext, ET_SIZE, "Error open file %s for appending",string);
      error(errortext, 500);
    }
    else                                              // Create header to new file
    {
      fprintf(p_log," ------------------------------------------------------------------------------------------\n");
      fprintf(p_log,"|  Decoder statistics. This file is made first time, later runs are appended               |\n");
      fprintf(p_log," ------------------------------------------------------------------------------------------ \n");
      fprintf(p_log,"| Date  | Time  |    Sequence        |#Img|Format|SNRY 1|SNRU 1|SNRV 1|SNRY N|SNRU N|SNRV N|\n");
      fprintf(p_log," ------------------------------------------------------------------------------------------\n");
    }
  }
  else
  { 
    fclose(p_log);
    p_log=fopen(string,"a");                    // File exist,just open for appending
  }

  now = time ((time_t *) NULL); // Get the system time and put it into 'now' as 'calender time'
  time (&now);
  l_time = localtime (&now);
  strftime (string, sizeof string, "%d-%b-%Y", l_time);
  fprintf(p_log,"| %1.5s |",string );

  strftime (string, sizeof string, "%H:%M:%S", l_time);
  fprintf(p_log,"| %1.5s |",string );

  fprintf(p_log,"%20.20s|",inp->infile);

  fprintf(p_log,"%3d |",img->number);

  fprintf(p_log,"%6.3f|",snr->snr_sum_y);
  fprintf(p_log,"%6.3f|",snr->snr_sum_u);
  fprintf(p_log,"%6.3f|\n",snr->snr_sum_v);

  fclose(p_log);

  snprintf(string, OUTSTRING_SIZE,"%s", DATADECFILE);
  p_log=fopen(string,"a");

  if(Bframe_ctr != 0) // B picture used
  {
    fprintf(p_log, "%3d %2d %2.2f %5d "
      "%2.2f %2.2f %2.2f %5d "
      "%2.2f %2.2f %2.2f %5d %.3f\n",
      img->number, 0, img->qp,
      0,
      0.0,
      0.0,
      0.0,
      0,
      snr->snr_sum_y,
      snr->snr_sum_u,
      snr->snr_sum_v,
      0,
      (double)0.001*tot_time/(img->number+Bframe_ctr-1));
  }
  else
  {
    fprintf(p_log, "%3d %2d %2.2f %5d "
      "%2.2f %2.2f %2.2f %5d "
      "%2.2f %2.2f %2.2f %5d %.3f\n",
      img->number, 0, img->qp,
      0,
      0.0,
      0.0,
      0.0,
      0,
      snr->snr_sum_y,
      snr->snr_sum_u,
      snr->snr_sum_v,
      0,
      (double)0.001*tot_time/img->number);
  }
  fclose(p_log);
}

/*
*************************************************************************
* Function:Allocates a Bitstream
* Input:
* Output:allocated Bitstream point
* Return: 
* Attention:
*************************************************************************
*/

Bitstream *AllocBitstream()
{
  Bitstream *bitstream;

  bitstream = (Bitstream *) calloc(1, sizeof(Bitstream));
  if (bitstream == NULL)
  {
    snprintf(errortext, ET_SIZE, "AllocBitstream: Memory allocation for Bitstream failed");
    error(errortext, 100);
  }
  bitstream->streamBuffer = (uchar *) calloc(MAX_CODED_FRAME_SIZE, sizeof(uchar));
  if (bitstream->streamBuffer == NULL)
  {
    snprintf(errortext, ET_SIZE, "AllocBitstream: Memory allocation for streamBuffer failed");
    error(errortext, 100);
  }

  return bitstream;
}


/*
*************************************************************************
* Function:Frees a partition structure (array).  
* Input:Partition to be freed, size of partition Array (Number of Partitions)
* Output:
* Return: 
* Attention:n must be the same as for the corresponding call of AllocPartition
*************************************************************************
*/

void FreeBitstream ()
{
  assert (currStream!= NULL);
  assert (currStream->streamBuffer != NULL);

  free (currStream->streamBuffer);
  free (currStream);
}

/*
*************************************************************************
* Function:Dynamic memory allocation of frame size related global buffers
buffers are defined in global.h, allocated memory must be freed in
void free_global_buffers()
* Input:Input Parameters inp_params *inp, Image Parameters img_params *img
* Output:Number of allocated bytes
* Return: 
* Attention:
*************************************************************************
*/


int init_global_buffers(inp_params *inp, img_params *img)
{
  int i,j;
  int refnum;

  int memory_size=0;
  
  int img_height = img->height;
  int img_width = img->width;
  int img_heightc = img->height_cr;
  int img_widthc = img->width_cr;

  int img_org_width = img_width - img->auto_crop_right;
  int img_org_height = img_height - img->auto_crop_bottom;
  int pic_luma_size_pad = (img_height + 2*IMG_PAD_SIZE) * (img_width + 2*IMG_PAD_SIZE);
  int pic_chroma_size_pad = pic_luma_size_pad >> 2;

  int buf_offset_y = img->iStride * IMG_PAD_SIZE + IMG_PAD_SIZE;
  int buf_offset_uv = (img->iStrideC * IMG_PAD_SIZE / 2) + (IMG_PAD_SIZE / 2);

  img->buf_cycle = inp->buf_cycle+1;

  img->buf_cycle *= 2;

  // allocate memory for reconstructed image
  //img_rec = (uchar_t*)malloc(img_width * img_height * 3/2);

  // allocate memory for img_prev
  img_prev = (uchar_t*)malloc(img_org_width * img_org_height * 3/2);

  // allocate memory for reference frames of each block: refFrArr
  memory_size += get_mem2Dint(&refFrArr_frm, img_height/B8_SIZE, img_width/B8_SIZE);


  // allocate memory in structure img
  if(((mb_data) = (Macroblock *) calloc((img->width/MB_SIZE) * (img_height /*vertical_size*/ /MB_SIZE),sizeof(Macroblock))) == NULL)
    no_mem_exit("init global buffers: mb_data");

  if(((img->intra_block) = (int**)calloc((j=(img->width/MB_SIZE) * (img_height /*vertical_size*/ /MB_SIZE)),sizeof(int))) == NULL)
    no_mem_exit("init global buffers: img->intra_block");
  for (i=0; i<j; i++)
  {
    if ((img->intra_block[i] = (int*)calloc(4, sizeof(int))) == NULL)
      no_mem_exit ("init global buffers: img->intra_block");
  }

  memory_size += get_mem3Dint(&(img->mv_frm),img->width/B8_SIZE +4, img_height /*vertical_size*/ /B8_SIZE,3);
  memory_size += get_mem3Dint(&(img->bimv),img->width/B8_SIZE +4, img_height/B8_SIZE, 3);
  if(progressive_sequence)    
      memory_size += get_mem2Dint(&(img->ipredmode), img->width / B4_SIZE + 2, img_height /*vertical_size*/ / B4_SIZE + 2);
  else
      memory_size += get_mem2Dint(&(img->ipredmode), img->width / B4_SIZE * 2 + 4, (vertical_size + 32) / (2 * B4_SIZE) * 4 + 4);
  memory_size += get_mem3Dint(&(img->dfMV),img->width/B8_SIZE +4, img_height /*vertical_size*/ /B8_SIZE,3);
  memory_size += get_mem3Dint(&(img->dbMV),img->width/B8_SIZE +4, img_height /*vertical_size*/ /B8_SIZE,3);
  memory_size += get_mem2Dint(&(img->fw_refFrArr_frm),img_height /*vertical_size*/ /B8_SIZE,img->width/B8_SIZE);
  memory_size += get_mem2Dint(&(img->bw_refFrArr_frm),img_height /*vertical_size*/ /B8_SIZE,img->width/B8_SIZE);
  memory_size += get_mem3Dint(&(img->fw_mv),img->width/B8_SIZE +4, img_height /*vertical_size*/ /B8_SIZE,3);
  memory_size += get_mem3Dint(&(img->bw_mv),img->width/B8_SIZE +4, img_height /*vertical_size*/ /B8_SIZE,3);


  img->buf_cycle = inp->buf_cycle+1;

	// allocate buffers for reference frames
    for(refnum=0 ; refnum<img->max_ref_num+1 ; refnum++){
		reference_frame[refnum][0] = (uchar_t *)malloc(pic_luma_size_pad);
		reference_frame[refnum][1] = (uchar_t *)malloc(pic_chroma_size_pad);
		reference_frame[refnum][2] = (uchar_t *)malloc(pic_chroma_size_pad);
    }
       
    //forward reference frame buffer
    for(i = 0 ; i < img->max_ref_num+1 ; i++)
    {
        p_ref_frm[i][0] = reference_frame[i][0] + buf_offset_y;
		p_ref_frm[i][1] = reference_frame[i][1] + buf_offset_uv;
		p_ref_frm[i][2] = reference_frame[i][2] + buf_offset_uv;
    }
    p_cur_frm[0] = reference_frame[img->max_ref_num][0] + buf_offset_y;
	p_cur_frm[1] = reference_frame[img->max_ref_num][1] + buf_offset_uv;
	p_cur_frm[2] = reference_frame[img->max_ref_num][2] + buf_offset_uv;

    //luma for backward
    //forward/backward reference buffer
    f_ref_frm = p_ref_frm[1]; // ref_index=0 for B frame,
    b_ref_frm = p_ref_frm[0]; // ref_index=0 for B frame, 

    return (memory_size);
}

/*
*************************************************************************
* Function:Free allocated memory of frame size related global buffers
buffers are defined in global.h, allocated memory is allocated in
int init_global_buffers()
* Input:Input Parameters inp_params *inp, Image Parameters img_params *img
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void free_global_buffers(img_params *img)
{
  int  i,j;

  free(img_prev);

  // free mem, allocated for structure img
  if (mb_data       != NULL) free(mb_data);

  j = (img->PicWidthInMbs)*(img->PicHeightInMbs);
  for (i=0; i<j; i++)
  {
    free (img->intra_block[i]);
  }

  free (img->intra_block);
  free_mem3Dint(img->mv_frm,img->width/B8_SIZE + 4);

  free_mem3Dint(img->bimv,img->width/B8_SIZE + 4);

  free_mem2Dint (img->ipredmode);

  free_mem3Dint(img->dfMV,img->width/B8_SIZE + 4);
  free_mem3Dint(img->dbMV,img->width/B8_SIZE + 4);


  free_mem2Dint(img->fw_refFrArr_frm);
  free_mem2Dint(img->bw_refFrArr_frm);

  free_mem3Dint(img->fw_mv,img->width/B8_SIZE + 4);
  free_mem3Dint(img->bw_mv,img->width/B8_SIZE + 4);

  for (i=0; i<3; i++){
	  for(j=0;j<3; j++){
		  free(reference_frame[i][j]);
	  }
  }

}

int get_direct_mv (int****** mv,int mb_x,int mb_y)
{
  int i, j, k, l;

  if ((*mv = (int*****)calloc(mb_y,sizeof(int****))) == NULL)
    no_mem_exit ("get_mem_mv: mv");
  for (i=0; i<mb_y; i++)
  {
    if (((*mv)[i] = (int****)calloc(mb_x,sizeof(int***))) == NULL)
      no_mem_exit ("get_mem_mv: mv");
    for (j=0; j<mb_x; j++)
    {
      if (((*mv)[i][j] = (int***)calloc(2,sizeof(int**))) == NULL)
        no_mem_exit ("get_mem_mv: mv");

      for (k=0; k<2; k++)
      {
        if (((*mv)[i][j][k] = (int**)calloc(2,sizeof(int*))) == NULL)
          no_mem_exit ("get_mem_mv: mv");
        for (l=0; l<2; l++)
          if (((*mv)[i][j][k][l] = (int*)calloc(3,sizeof(int))) == NULL)
            no_mem_exit ("get_mem_mv: mv");
      }
    }
  }
  return mb_x*mb_y*2*2*3*sizeof(int);
}

/*
*************************************************************************
* Function:Free memory from mv
* Input:int****** mv
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void free_direct_mv (int***** mv,int mb_x,int mb_y)
{
  int i, j, k, l;

  for (i=0; i<mb_y; i++)
  {
    for (j=0; j<mb_x; j++)
    {
      for (k=0; k<2; k++)
      {
        for (l=0; l<2; l++)
          free (mv[i][j][k][l]);

        free (mv[i][j][k]);
      }
      free (mv[i][j]);
    }
    free (mv[i]);
  }
  free (mv);
}

/*
*************************************************************************
* Function:update the decoder picture buffer
* Input:frame number in the bitstream and the video sequence
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void Update_Picture_Buffers()
{ 
	int i;

	if(img->p_subtype==2)
	{
		return;
	}

	if(img->p_subtype==3)
	{
		//forward/backward reference buffer
		f_ref_frm = p_ref_frm[0]; // ref_index=0 for B frame, 
		b_ref_frm = p_ref_frm[1]; // ref_index=0 for B frame, 

		return;
	}

	// update reference frames, append the new encoded frame to reference buffer 
	for(i = img->max_ref_num-1 ; i>0 ; i--)
	{
		p_ref_frm[i][0] = p_ref_frm[i-1][0];
		p_ref_frm[i][1] = p_ref_frm[i-1][1];
		p_ref_frm[i][2] = p_ref_frm[i-1][2];
	}
	for(i = 0; i < 3; i++){
		p_ref_frm[0][i] = p_cur_frm[i];
		p_cur_frm[i] = p_ref_frm[img->max_ref_num-1][i];
	}
  //forward/backward reference buffer
  f_ref_frm = p_ref_frm[1]; // ref_index=0 for B frame, 
  b_ref_frm = p_ref_frm[0]; // ref_index=0 for B frame,
}


/*!
************************************************************************
* \brief
*    Allocates a stand-alone partition structure.  Structure should
*    be freed by FreePartition();
*    data structures
*
* \par Input:
*    n: number of partitions in the array
* \par return
*    pointer to DataPartition Structure, zero-initialized
*  added by  
************************************************************************
*/

DataPartition *AllocPartition(int n)
{
  DataPartition *partArr, *dataPart;
  int i;

  partArr = (DataPartition *) calloc(n, sizeof(DataPartition));
  if (partArr == NULL)
  {
    snprintf(errortext, ET_SIZE, "AllocPartition: Memory allocation for Data Partition failed");
    error(errortext, 100);
  }

  for (i=0; i<n; i++) // loop over all data partitions
  {
    dataPart = &(partArr[i]);
    dataPart->bitstream = (Bitstream *) calloc(1, sizeof(Bitstream));
    if (dataPart->bitstream == NULL)
    {
      snprintf(errortext, ET_SIZE, "AllocPartition: Memory allocation for Bitstream failed");
      error(errortext, 100);
    }
  }
  return partArr;
}

/*!
************************************************************************
* \brief
*    Allocates the slice structure along with its dependent
*    data structures
*
* \par Input:
*    Input Parameters inp_params *inp,  img_params *img
* \author
* 
************************************************************************
*/
void malloc_slice(inp_params *inp, img_params *img)
{
  Slice *currSlice;

  img->currentSlice = (Slice *) calloc(1, sizeof(Slice));
  if ( (currSlice = img->currentSlice) == NULL)
  {
    snprintf(errortext, ET_SIZE, "Memory allocation for Slice datastruct in NAL-mode %d failed", inp->FileFormat);
    error(errortext,100);
  }
    // create all context models
    currSlice->mot_ctx = create_contexts_MotionInfo();
    currSlice->tex_ctx = create_contexts_TextureInfo();

  currSlice->max_part_nr = 3;  //! assume data partitioning (worst case) for the following mallocs()
  currSlice->partArr = AllocPartition(currSlice->max_part_nr);
}
/*!
************************************************************************
* \brief
*    Memory frees of the Slice structure and of its dependent
*    data structures
*
* \par Input:
*    Input Parameters inp_params *inp,  img_params *img
* \author
* 
************************************************************************
*/
void free_slice(img_params *img)
{
  Slice *currSlice = img->currentSlice;

  FreePartition (currSlice->partArr);

    // delete all context models
    delete_contexts_MotionInfo(currSlice->mot_ctx);
    delete_contexts_TextureInfo(currSlice->tex_ctx);

  free(img->currentSlice);

  currSlice = NULL;
}
/*!
************************************************************************
* \brief
*    Frees a partition structure (array).  
*
* \par Input:
*    Partition to be freed, size of partition Array (Number of Partitions)
*
* \par return
*    None
*
* \note
*    n must be the same as for the corresponding call of AllocPartition
* \author : 
************************************************************************
*/
void FreePartition (DataPartition *dp)
{
  assert (dp != NULL);
  assert (dp->bitstream != NULL);

    assert (dp->bitstream->streamBuffer != NULL);
  free (dp);
}

